package com.codedancer.campus.client.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codedancer.campus.client.service.ILostFoundItemService;
import com.codedancer.campus.client.service.bo.lostFoundItem.LostFoundItemAddOrUpdateBo;
import com.codedancer.campus.client.service.bo.lostFoundItem.LostFoundItemPageSearchBo;
import com.codedancer.campus.client.service.vo.lostFoundItem.LostFoundItemVo;
import com.codedancer.campus.common.dataresource.ExternalApiData;
import com.codedancer.campus.common.enums.ViewNumberKeyEnum;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.common.utils.RedisUtil;
import com.codedancer.campus.common.utils.UUIDGenerator;
import com.codedancer.campus.enums.LostFoundItemStatus;
import com.codedancer.campus.enums.LostFoundItemType;
import com.codedancer.campus.mapper.CategoryMapper;
import com.codedancer.campus.mapper.LostFoundItemImageMapper;
import com.codedancer.campus.mapper.LostFoundItemMapper;
import com.codedancer.campus.mapper.UserSchoolMapper;
import com.codedancer.campus.po.Category;
import com.codedancer.campus.po.LostFoundItem;
import com.codedancer.campus.po.LostFoundItemImage;
import com.codedancer.campus.po.UserSchool;
import com.codedancer.campus.qo.lostFoundItem.LostFoundItemPageSearchQo;

import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Exception.class)
public class LostFoundItemServiceImpl implements ILostFoundItemService {

    @Autowired
    private LostFoundItemMapper lostFoundItemMapper;
    @Autowired
    private UserSchoolMapper userSchoolMapper;
    @Autowired
    private LostFoundItemImageMapper lostFoundItemImageMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private RedisUtil redisUtil;
    // 注入浏览记录redisTemplate
    @Resource(name = "viewRedisTemplate")
    private StringRedisTemplate viewRedisTemplate;
    @Autowired
    private ExternalApiData externalApiData;

    /**
     * 发布物品
     *
     * @param lostFoundItemAddOrUpdateBo
     */
    @Override
    public void publish(LostFoundItemAddOrUpdateBo lostFoundItemAddOrUpdateBo) {
        Category category = categoryMapper.findById(lostFoundItemAddOrUpdateBo.getCategoryUuid())
            .orElseThrow(() -> new BusinessException("分类不存在"));
        if (CollUtil.isEmpty(lostFoundItemAddOrUpdateBo.getImageUrls())) {
            throw new BusinessException("请至少上传一张图片");
        }
        if (externalApiData.checkSensitiveWords(lostFoundItemAddOrUpdateBo.getName()) || externalApiData.checkSensitiveWords(lostFoundItemAddOrUpdateBo.getDescription())) {
            throw new BusinessException("物品名称或描述存在敏感词，请检查");
        }
        LostFoundItem lostFoundItem = BeanUtil.copyProperties(lostFoundItemAddOrUpdateBo,
            LostFoundItem.class);
        lostFoundItem.setUuid(UUIDGenerator.getUUID());
        // 获取发布人学校
        UserSchool userSchool = userSchoolMapper.selectOneByColumn("user_uuid",
            lostFoundItemAddOrUpdateBo.getCurrentUserUuid());
        lostFoundItem.setPublishUserUuid(lostFoundItemAddOrUpdateBo.getCurrentUserUuid());
        lostFoundItem.setPublishSchoolUuid(userSchool.getSchoolUuid());
        lostFoundItem.setType(LostFoundItemType.fromValue(lostFoundItemAddOrUpdateBo.getType()));
        lostFoundItem.setStatus(LostFoundItemStatus.PENDING_REVIEW);
        lostFoundItem.setCategoryUuid(category.getUuid());
        lostFoundItem.setPlateUuid(category.getPlateUuid());
        lostFoundItemMapper.insert(lostFoundItem);
        // 保存图片
        for (String imageUrl : lostFoundItemAddOrUpdateBo.getImageUrls()) {
            LostFoundItemImage lostFoundItemImage = LostFoundItemImage.builder()
                .imageUrl(imageUrl)
                .lostFoundItemUuid(lostFoundItem.getUuid())
                .uuid(UUIDGenerator.getUUID())
                .build();
            lostFoundItemImageMapper.insert(lostFoundItemImage);
        }
    }

    /**
     * 分页查询物品
     *
     * @param lostFoundItemPageSearchBo
     * @return
     */
    @Override
    public IPage<LostFoundItemVo> page(LostFoundItemPageSearchBo lostFoundItemPageSearchBo) {
        LostFoundItemPageSearchQo lostFoundItemPageSearchQo = BeanUtil.copyProperties(
            lostFoundItemPageSearchBo, LostFoundItemPageSearchQo.class);
        UserSchool userSchool = userSchoolMapper.selectOneByColumn("user_uuid",
            lostFoundItemPageSearchBo.getCurrentUserUuid());
        lostFoundItemPageSearchQo.setPublishSchoolUuid(userSchool.getSchoolUuid());
        IPage<LostFoundItem> lostFoundItemIPage = lostFoundItemMapper.page(
            new Page<LostFoundItem>(lostFoundItemPageSearchBo.getPage(),
                lostFoundItemPageSearchBo.getSize()), lostFoundItemPageSearchQo);
        IPage<LostFoundItemVo> lostFoundItemVoIPage = new Page<>();
        List<LostFoundItemVo> lostFoundItemVos;
        lostFoundItemVos = lostFoundItemIPage.getRecords().stream().map(lostFoundItem -> {
            LostFoundItemVo lostFoundItemVo = BeanUtil.copyProperties(lostFoundItem,
                LostFoundItemVo.class);
            lostFoundItemVo.setCategoryName(lostFoundItem.getCategory().getName());
            lostFoundItemVo.setPublishNickName(lostFoundItem.getPublishUser().getNickName());
            lostFoundItemVo.setPublishSchoolName(lostFoundItem.getPublishSchool().getName());
            // 获取图片信息
            List<LostFoundItemImage> lostFoundItemImages = lostFoundItemImageMapper
                .selectListByColumn(
                    "lost_found_item_uuid", lostFoundItem.getUuid());
            lostFoundItemVo.setFirstImage(lostFoundItemImages.get(0).getImageUrl());
            return lostFoundItemVo;
        }).collect(Collectors.toList());
        lostFoundItemVoIPage.setTotal(lostFoundItemIPage.getTotal());
        lostFoundItemVoIPage.setRecords(lostFoundItemVos);
        return lostFoundItemVoIPage;
    }

    /**
     * 详情
     *
     * @param uuid
     * @return
     */
    @Override
    public LostFoundItemVo detail(String uuid) {
        redisUtil.setRedisTemplate(viewRedisTemplate);
        LostFoundItem lostFoundItem = lostFoundItemMapper.detail(uuid);
        if (ObjectUtil.isEmpty(lostFoundItem)) {
            throw new BusinessException("物品不存在");
        }
        LostFoundItemVo lostFoundItemVo = BeanUtil.copyProperties(lostFoundItem,
            LostFoundItemVo.class);
        lostFoundItemVo.setPublishNickName(lostFoundItem.getPublishUser().getNickName());
        lostFoundItemVo.setPublishSchoolName(lostFoundItem.getPublishSchool().getName());
        lostFoundItemVo.setPublishUserAvatar(lostFoundItem.getPublishUser().getAvatar());
        lostFoundItemVo.setPublishUserUuid(lostFoundItem.getPublishUser().getUuid());
        // 获取图片信息
        List<LostFoundItemImage> lostFoundItemImages = lostFoundItemImageMapper.selectListByColumn(
            "lost_found_item_uuid", lostFoundItem.getUuid());
        lostFoundItemVo.setImages(
            lostFoundItemImages.stream().map(LostFoundItemImage::getImageUrl).collect(
                Collectors.toList()));
        // 获取浏览次数
        Long size = redisUtil.size(ViewNumberKeyEnum.LOST_FOUND_ITEM + uuid);
        lostFoundItemVo.setViewNumber(size.intValue() + lostFoundItem.getViewNumber());
        // 获取分类
        Category category = categoryMapper.selectById(lostFoundItem.getCategoryUuid());
        lostFoundItemVo.setCategoryName(category.getName());
        return lostFoundItemVo;
    }

    /**
     * 分页查询用户物品
     *
     * @param lostFoundItemPageSearchBo
     * @return
     */
    @Override
    public IPage<LostFoundItemVo> page2User(LostFoundItemPageSearchBo lostFoundItemPageSearchBo) {
        LostFoundItemPageSearchQo lostFoundItemPageSearchQo = BeanUtil.copyProperties(
            lostFoundItemPageSearchBo, LostFoundItemPageSearchQo.class);
        IPage<LostFoundItem> lostFoundItemIPage = lostFoundItemMapper.page2User(
            new Page<LostFoundItem>(lostFoundItemPageSearchBo.getPage(),
                lostFoundItemPageSearchBo.getSize()), lostFoundItemPageSearchQo);
        IPage<LostFoundItemVo> lostFoundItemVoIPage = new Page<>();
        List<LostFoundItemVo> lostFoundItemVos;
        lostFoundItemVos = lostFoundItemIPage.getRecords().stream().map(lostFoundItem -> {
            LostFoundItemVo lostFoundItemVo = BeanUtil.copyProperties(lostFoundItem,
                LostFoundItemVo.class);
            lostFoundItemVo.setPublishNickName(lostFoundItem.getPublishUser().getNickName());
            lostFoundItemVo.setPublishSchoolName(lostFoundItem.getPublishSchool().getName());
            // 获取图片信息
            List<LostFoundItemImage> lostFoundItemImages = lostFoundItemImageMapper
                .selectListByColumn(
                    "lost_found_item_uuid", lostFoundItem.getUuid());
            lostFoundItemVo.setFirstImage(lostFoundItemImages.get(0).getImageUrl());
            return lostFoundItemVo;
        }).collect(Collectors.toList());
        lostFoundItemVoIPage.setTotal(lostFoundItemIPage.getTotal());
        lostFoundItemVoIPage.setRecords(lostFoundItemVos);
        return lostFoundItemVoIPage;
    }

    /**
     * 删除
     *
     * @param uuid
     */
    @Override
    public void delete(String uuid) {
        lostFoundItemMapper.deleteById(uuid);
    }

    /**
     * 确认认领
     *
     * @param uuid
     */
    @Override
    public void confirmClaim(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        lostFoundItem.setStatus(LostFoundItemStatus.CLAIMED);
        lostFoundItemMapper.updateById(lostFoundItem);
    }

    /**
     * 确认找到
     *
     * @param uuid
     */
    @Override
    public void confirmFind(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        lostFoundItem.setStatus(LostFoundItemStatus.FOUNDED);
        lostFoundItemMapper.updateById(lostFoundItem);
    }

    /**
     * 重新发布
     *
     * @param uuid
     */
    @Override
    public void reissue(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        // 判断是否是管理员撤回
        if (lostFoundItem.getIsAdminRevoke()) {
            throw new BusinessException("已被管理员撤回，请联系管理员");
        }
        // 判断物品发布类型
        if (lostFoundItem.getType().equals(LostFoundItemType.PICK_UP)) {
            lostFoundItem.setStatus(LostFoundItemStatus.NO_CLAIM);
        }
        if (lostFoundItem.getType().equals(LostFoundItemType.LOST)) {
            lostFoundItem.setStatus(LostFoundItemStatus.NO_FOUND);
        }
        lostFoundItemMapper.updateById(lostFoundItem);
    }

    /**
     * 修改物品
     *
     * @param lostFoundItemAddOrUpdateBo
     */
    @Override
    public void edit(LostFoundItemAddOrUpdateBo lostFoundItemAddOrUpdateBo) {
        LostFoundItem lostFoundItem = lostFoundItemMapper
            .findById(lostFoundItemAddOrUpdateBo.getUuid())
            .orElseThrow(() -> new BusinessException("物品不存在"));
        Category category = categoryMapper.findById(lostFoundItemAddOrUpdateBo.getCategoryUuid())
            .orElseThrow(() -> new BusinessException("分类不存在"));
        if (CollUtil.isEmpty(lostFoundItemAddOrUpdateBo.getImageUrls())) {
            throw new BusinessException("请至少上传一张图片");
        }
        if (externalApiData.checkSensitiveWords(lostFoundItemAddOrUpdateBo.getName()) || externalApiData.checkSensitiveWords(lostFoundItemAddOrUpdateBo.getDescription())) {
            throw new BusinessException("物品名称或描述存在敏感词，请检查");
        }
        BeanUtil.copyProperties(lostFoundItemAddOrUpdateBo, lostFoundItem);
        lostFoundItem.setType(LostFoundItemType.fromValue(lostFoundItemAddOrUpdateBo.getType()));
        lostFoundItem.setCategoryUuid(category.getUuid());
        lostFoundItem.setPlateUuid(category.getPlateUuid());
        lostFoundItem.setStatus(LostFoundItemStatus.PENDING_REVIEW);
        lostFoundItemMapper.updateById(lostFoundItem);
        // 先删除关联图片
        lostFoundItemImageMapper.deleteByColumn("lost_found_item_uuid", lostFoundItem.getUuid());
        // 保存图片
        for (String imageUrl : lostFoundItemAddOrUpdateBo.getImageUrls()) {
            LostFoundItemImage lostFoundItemImage = LostFoundItemImage.builder()
                .imageUrl(imageUrl)
                .lostFoundItemUuid(lostFoundItem.getUuid())
                .uuid(UUIDGenerator.getUUID())
                .build();
            lostFoundItemImageMapper.insert(lostFoundItemImage);
        }
    }

    /**
     * 同步自由广场
     *
     * @param uuid
     */
    @Override
    public void syncLibertySquare(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper
            .findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        if (!lostFoundItem.isCanSyncLibertySquareOrCancel()) {
            throw new BusinessException("物品状态错误或被管理员撤回，不能同步");
        }
        lostFoundItem.setIsSyncLibertySquare(true);
        lostFoundItemMapper.updateById(lostFoundItem);
    }

    /**
     * 取消同步自由广场
     *
     * @param uuid
     */
    @Override
    public void cancelSyncLibertySquare(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper
            .findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        if (!lostFoundItem.isCanSyncLibertySquareOrCancel()) {
            throw new BusinessException("物品状态错误或被管理员撤回，不能取消同步");
        }
        lostFoundItem.setIsSyncLibertySquare(false);
        lostFoundItemMapper.updateById(lostFoundItem);
    }

    /**
     * 撤回
     *
     * @param uuid
     */
    @Override
    public void revoke(String uuid) {
        LostFoundItem lostFoundItem = lostFoundItemMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("物品不存在"));
        if (!lostFoundItem.isCanRevoke()) {
            throw new BusinessException("物品状态错误或被管理员撤回，不能撤回");
        }
        lostFoundItem.setStatus(LostFoundItemStatus.RECALL);
        lostFoundItemMapper.updateById(lostFoundItem);
    }
}
